home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Orlando_1993 / Devcon93.4 / Networking2 / SANA2 / examples / device_funcs.c next >
Encoding:
C/C++ Source or Header  |  1993-01-11  |  45.5 KB  |  1,724 lines

  1. /*
  2. ** $Source: HOG:Other/networking/sana2/src/slip/RCS/device_funcs.c,v $
  3. ** $State: Exp $
  4. ** $Revision: 37.5 $
  5. ** $Date: 92/12/16 13:45:22 $
  6. ** $Author: bj $
  7. **
  8. ** Amiga SANA-II Example SLIP device driver.
  9. **
  10. ** (C) Copyright 1992 Commodore-Amiga, Inc.
  11. **
  12. */
  13.  
  14. #include "slip_device.h"
  15.  
  16. #include <dos/dostags.h>
  17. #include <dos/rdargs.h>
  18. #include <intuition/intuition.h>
  19.  
  20. #include <clib/exec_protos.h>
  21. #include <clib/dos_protos.h>
  22. #include <clib/utility_protos.h>
  23. #include <clib/timer_protos.h>
  24. #include <clib/alib_stdio_protos.h>
  25. #include <clib/intuition_protos.h>
  26.  
  27. #include <pragmas/exec_pragmas.h>
  28. #include <pragmas/dos_pragmas.h>
  29. #include <pragmas/utility_pragmas.h>
  30. #include <pragmas/timer_pragmas.h>
  31. #include <pragmas/intuition_pragmas.h>
  32.  
  33. #include <string.h>
  34. #include "device_protos.h"
  35.  
  36. /*
  37. ** External variables and functions
  38. **
  39. */
  40.  
  41. extern struct Library *ExtDeviceBase;
  42. extern VOID (*DevProcEntry)(VOID);
  43. extern ULONG IPToNum(STRPTR ipstr);
  44. extern VOID kprintf(STRPTR fmt, ...);
  45.  
  46. /*
  47. ** Device Open vector
  48. **
  49. ** a1 - SANA2 IO Request
  50. ** a6 - Pointer to our device base
  51. ** d0 - Unit number
  52. ** d1 - Flags
  53. **
  54. */
  55.  
  56. ULONG ASM DevOpen(REG(a1) struct IOSana2Req *ios2,
  57.           REG(d0) ULONG s2unit,
  58.           REG(d1) ULONG s2flags)
  59. {
  60.     struct SLIPDevice *SLIPDevice = SLIPBase;
  61.     struct SLIPDevUnit *sdu;
  62.     struct TagItem *bufftag;
  63.     struct Library *UtilityBase;
  64.     struct BufferManagement *bm;
  65.     ULONG returncode;
  66.     BOOL status = FALSE;
  67.  
  68.     /* Make sure our open remains single-threaded. */
  69.     ObtainSemaphore(&SLIPDevice->sd_Lock);    /* Enforce single threading since we may need to
  70.                                Wait() when starting up the Unit process */
  71.  
  72.     SLIPDevice->sd_Device.lib_OpenCnt++;    /* So we won't expunge ourselves... */
  73.  
  74.     if(s2unit < SD_MAXUNITS)    /* Legal Unit? */
  75.     {
  76.         if(sdu = InitSLIPUnit(s2unit))    /* Initialize the Unit */
  77.         {
  78.         if(UtilityBase = OpenLibrary("utility.library",37L)) /* For Tag functions */
  79.         {
  80.             /* Allocate a structure to store the pointers to the callback routines. */
  81.  
  82.             if(bm = AllocMem(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC))
  83.             {
  84.                 /* Note: I don't complain if I can't find pointers to the callback routines.
  85.                          This is because there are some programs that may need to open me, but
  86.                          will never use any device commands that require the callbacks. */
  87.  
  88.                 if(bufftag = FindTagItem(S2_CopyToBuff, (struct TagList *)ios2->ios2_BufferManagement))
  89.                 {
  90.                     bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
  91.                 }
  92.  
  93.                 if(bufftag = FindTagItem(S2_CopyFromBuff, (struct TagList *)ios2->ios2_BufferManagement))
  94.                 {
  95.                     bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
  96.                 }
  97.  
  98.                 AddTail((struct List *)&sdu->sdu_BuffMgmt,(struct Node *)bm);
  99.  
  100.             /* Everything went okay. */
  101.                 status = TRUE;
  102.             returncode = 0;
  103.                 SLIPDevice->sd_Device.lib_OpenCnt++;
  104.                 SLIPDevice->sd_Device.lib_Flags &=~LIBF_DELEXP;
  105.                 sdu->sdu_Unit.unit_OpenCnt++;
  106.  
  107.             /* Fix up the initial io request */
  108.                     ios2->ios2_BufferManagement = (VOID *)bm;
  109.                 ios2->ios2_Req.io_Error = 0;
  110.                 ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
  111.                 ios2->ios2_Req.io_Unit = sdu;
  112.                 ios2->ios2_Req.io_Device = SLIPDevice;
  113.             }
  114.             CloseLibrary(UtilityBase);
  115.         }
  116.     }
  117.     }
  118.     /* See if something went wrong. */
  119.     if(!status)
  120.     {
  121.         ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
  122.         ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  123.         ios2->ios2_Req.io_Device = (struct Device *) -1;
  124.         returncode = IOERR_OPENFAIL;
  125.     }
  126.     SLIPDevice->sd_Device.lib_OpenCnt--;
  127.     ReleaseSemaphore(&SLIPDevice->sd_Lock);
  128.  
  129.     return(returncode);
  130. }
  131.  
  132. /*
  133. ** Device Close vector.
  134. **
  135. ** a1 - IOReq
  136. ** a6 - Device Pointer
  137. **
  138. */
  139.  
  140. BPTR ASM DevClose(REG(a1) struct IOSana2Req *ios2)
  141. {
  142.     struct SLIPDevice *SLIPDevice = SLIPBase;
  143.     struct SLIPDevUnit *sdu;
  144.     BPTR seglist = 0L;
  145.  
  146.     ObtainSemaphore(&SLIPDevice->sd_Lock);
  147.  
  148.     sdu = (struct SLIPDevUnit *)ios2->ios2_Req.io_Unit;
  149.  
  150.     /* Trash the io_Device and io_Unit fields so that any attempt to use this
  151.        request will die immediatly. */
  152.  
  153.     ios2->ios2_Req.io_Device = (struct Device *) -1;
  154.     ios2->ios2_Req.io_Unit = (struct Unit *) -1;
  155.  
  156.     /* I always shut the unit process down if the open count drops to zero.
  157.        That way, if I need to expunge, I never have to Wait(). */
  158.  
  159.     sdu->sdu_Unit.unit_OpenCnt--;
  160.     if(!sdu->sdu_Unit.unit_OpenCnt)
  161.     {
  162.         ExpungeUnit(sdu);
  163.     }
  164.  
  165.     SLIPDevice->sd_Device.lib_OpenCnt--;
  166.  
  167.     ReleaseSemaphore(&SLIPDevice->sd_Lock);
  168.  
  169.     /* Check to see if we've been asked to expunge. */
  170.     if(SLIPDevice->sd_Device.lib_Flags & LIBF_DELEXP)
  171.         seglist = DevExpunge();
  172.  
  173.     return(seglist);
  174. }
  175.  
  176.  
  177. /*
  178. ** Device Expunge vector
  179. **
  180. ** a6 - Device base
  181. **
  182. ** Note: You may NEVER EVER Wait() in expunge. Period.
  183. **      Don't even *think* about it.
  184. */
  185.  
  186. BPTR ASM DevExpunge(VOID)
  187. {
  188.     struct SLIPDevice *SLIPDevice = SLIPBase;
  189.     BPTR seglist;
  190.     ULONG devbase;
  191.     LONG devbasesize;
  192.  
  193.     if(SLIPDevice->sd_Device.lib_OpenCnt)
  194.     {
  195.         /* Sorry, we're busy.  We'll expunge later on
  196.            if we can. */
  197.         SLIPDevice->sd_Device.lib_Flags |= LIBF_DELEXP;
  198.         seglist = (BPTR)0L;
  199.     }
  200.     else
  201.     {
  202.         /* Free up our library base and function table after
  203.            removing ourselves from the library list. */
  204.         Remove((struct Node *)SLIPDevice);
  205.         seglist = SLIPDevice->sd_SegList;
  206.  
  207.         devbase = (ULONG) SLIPDevice;
  208.  
  209.         devbasesize = (ULONG)SLIPDevice->sd_Device.lib_NegSize;
  210.         devbase = devbase - devbasesize;
  211.  
  212.         devbasesize += (ULONG)SLIPDevice->sd_Device.lib_PosSize;
  213.  
  214.         FreeMem((APTR)devbase,devbasesize);
  215.     }
  216.     return(seglist);
  217. }
  218.  
  219. /*
  220. ** InitSLIPUnit
  221. **
  222. ** Initialize (if needed) a new SLIP device Unit and process.
  223. **
  224. */
  225.  
  226. struct SLIPDevUnit *InitSLIPUnit(ULONG s2unit)
  227. {
  228.     struct SLIPDevice *SLIPDevice = SLIPBase;
  229.     struct SLIPDevUnit *sdu;
  230.     struct TagItem NPTags[]={NP_Entry, 0, NP_Name, 0, NP_Priority, SLIP_PRI, TAG_DONE, 0};
  231.     struct MsgPort *replyport;
  232.  
  233.     /* Check to see if the Unit is already up and running.  If
  234.        it is, just drop through.  If not, try to start it up. */
  235.  
  236.     if(!SLIPDevice->sd_Units[s2unit])
  237.     {
  238.         /* Open up dos.library */
  239.         if(SLIPDevice->sd_DOSBase = OpenLibrary("dos.library",37L))
  240.         {
  241.             /* Allocate a new Unit structure */
  242.             if(sdu = AllocMem(sizeof(struct SLIPDevUnit), MEMF_CLEAR|MEMF_PUBLIC))
  243.             {
  244.                 /* Do some initialization on the Unit structure */
  245.  
  246.                 NewList(&sdu->sdu_Unit.unit_MsgPort.mp_MsgList);
  247.                 sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
  248.                 sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
  249.                 sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Name = "slip.device";
  250.  
  251.                 sdu->sdu_UnitNum = s2unit;
  252.                 sdu->sdu_Device = (struct Device *) SLIPDevice;
  253.  
  254.         /* Try to read in our configuration file */
  255.                 if(ReadConfig(sdu))
  256.                 {
  257.                     /* Start up the unit process */
  258.                     if(replyport = CreateMsgPort())
  259.                     {
  260.                         SLIPDevice->sd_Startup.Msg.mn_ReplyPort = replyport;
  261.                         SLIPDevice->sd_Startup.Device = (struct Device *) SLIPDevice;
  262.                         SLIPDevice->sd_Startup.Unit = (struct Unit *)sdu;
  263.  
  264.                         NPTags[0].ti_Data = (ULONG) &DevProcEntry;       /* Assembly entry point for the unit process. */
  265.                         NPTags[1].ti_Data = (ULONG) "slip.device";      /* Process name */
  266.  
  267.             ExtDeviceBase = (struct Library *)SLIPDevice;
  268.  
  269.                         if(sdu->sdu_Proc = CreateNewProc(NPTags))
  270.                         {
  271.                             PutMsg(&sdu->sdu_Proc->pr_MsgPort,(struct Message *)&SLIPDevice->sd_Startup);
  272.                             WaitPort(replyport);
  273.                             GetMsg(replyport);
  274.                         }
  275.                         DeleteMsgPort(replyport);
  276.                     }
  277.                 }
  278.  
  279.                 if(!sdu->sdu_Proc)
  280.                 {
  281.                     /* The Unit process couldn't start for some reason, so free the Unit structure. */
  282.                     FreeMem(sdu,sizeof(struct SLIPDevUnit));
  283.                 }
  284.                 else
  285.                 {
  286.                     /* Set up the Unit structure pointer in the device base */
  287.                     SLIPDevice->sd_Units[s2unit] = (struct Unit *)sdu;
  288.                 }
  289.             }
  290.             CloseLibrary(SLIPDevice->sd_DOSBase);
  291.         }
  292.     }
  293.     return((struct SLIPDevUnit *)SLIPDevice->sd_Units[s2unit]);
  294. }
  295.  
  296. /*
  297. **
  298. ** ExpungeUnit
  299. **
  300. ** Tells a unit process to go away...
  301. **
  302. ** This function is called from the DevClose routine when the open count for a
  303. ** unit reaches zero.  This routine signals the unit process to exit and then
  304. ** waits for the unit process to acknowledge.  The unit structure is then
  305. ** freed.
  306. */
  307.  
  308. VOID ExpungeUnit(struct SLIPDevUnit *sdu)
  309. {
  310.     struct SLIPDevice *SLIPDevice = SLIPBase;
  311.     struct Task *unittask;
  312.  
  313.     unittask = (struct Task *)sdu->sdu_Proc;
  314.  
  315.     sdu->sdu_Proc = (struct Process *)FindTask(0L);
  316.  
  317.     Signal(unittask,SIGBREAKF_CTRL_F);
  318.     Wait(SIGBREAKF_CTRL_F);
  319.  
  320.     SLIPDevice->sd_Units[sdu->sdu_UnitNum] = NULL;
  321.  
  322.     FreeMem(sdu, sizeof(struct SLIPDevUnit));
  323. }
  324.  
  325. /*
  326. **
  327. ** ReadConfig
  328. **
  329. ** Attempt to read in and parse the driver's configuration file.
  330. **
  331. ** The files are named by ENV:SANA2/slipX.config where X is the decimal
  332. ** representation of the device's unit number.
  333. **
  334. */
  335.  
  336. BOOL ReadConfig(struct SLIPDevUnit *sdu)
  337. {
  338.     UBYTE *linebuff,buff[40];
  339.     STRPTR termchar;
  340.     struct RDArgs *rdargs;
  341.     BPTR ConfigFile;
  342.     LONG args[6];
  343.     BOOL status = FALSE;
  344.     ULONG linenum=0;
  345.     UWORD i;
  346.  
  347.     /* Create the name of our config file.. */
  348.     sprintf(buff,"ENV:SANA2/slip%ld.config",(ULONG)sdu->sdu_UnitNum);
  349.  
  350.     /* ...and open it. */
  351.     if(ConfigFile = Open(buff,MODE_OLDFILE))
  352.     {
  353.         /* Here, I use ReadArgs() to do the file parsing for me. */
  354.  
  355.         if(linebuff = AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC))
  356.         {
  357.             if(rdargs = AllocDosObject(DOS_RDARGS, NULL))
  358.             {
  359.                 while(FGets(ConfigFile, linebuff, 255))
  360.                 {
  361.                     linenum++;
  362.                     if(linebuff[0] == '#') /* Skip comment lines */
  363.                         continue;
  364.  
  365.                     rdargs->RDA_Source.CS_Buffer = linebuff;
  366.                     rdargs->RDA_Source.CS_Length = 256;
  367.                     rdargs->RDA_Source.CS_CurChr = 0;
  368.  
  369.                     /* ReadArgs() requires that the line be null-terminated
  370.                        or funny things happen. */
  371.  
  372.                     termchar = (STRPTR) linebuff + strlen(linebuff);
  373.                     *termchar = '\n';
  374.                     termchar++;
  375.                     *termchar = 0;
  376.  
  377.                     for(i = 0; i< 6; i++)
  378.                         args[i]=0;
  379.  
  380.             /* Parse the line...*/
  381.  
  382.                     if(ReadArgs("SERNAME/A,SERUNIT/A/N,SERBAUD/A/N,IPSTR/A,CD=CARRIERDETECT/S,7WIRE/S",args,rdargs))
  383.                     {
  384.             strcpy(sdu->sdu_SerDevName,(STRPTR)args[0]);
  385.             sdu->sdu_SerUnitNum = *((ULONG *)args[1]);
  386.             sdu->sdu_BaudRate = *((ULONG *)args[2]);
  387.             sdu->sdu_StAddr = IPToNum((STRPTR)args[3]);
  388.  
  389.             if(args[4])
  390.                 sdu->sdu_State |= SLIPUF_CD;
  391.  
  392.             if(args[5])
  393.                 sdu->sdu_State |= SLIPUF_7WIRE;
  394.  
  395.             status = TRUE;
  396.             FreeArgs(rdargs);
  397.             break;
  398.             }
  399.             else
  400.                     {
  401.                         struct Library *IntuitionBase;
  402.                         struct EasyStruct es;
  403.                         if(IntuitionBase = OpenLibrary("intuition.library",37L))
  404.                         {
  405.                             es.es_StructSize=sizeof(struct EasyStruct);
  406.                             es.es_Flags=0;
  407.                             es.es_Title="Slip.device";
  408.                             es.es_TextFormat="Error in configuration file on line %ld.";
  409.                             es.es_GadgetFormat="Okay";
  410.                             EasyRequestArgs(NULL, &es, 0, &linenum);
  411.                             CloseLibrary(IntuitionBase);
  412.                         }
  413.                         break;
  414.                     }
  415.  
  416.         }
  417.         FreeDosObject(DOS_RDARGS,rdargs);
  418.         }
  419.         FreeMem(linebuff, 256);
  420.     }
  421.     Close(ConfigFile);
  422.     }
  423.     return(status);
  424. }                 
  425.  
  426.  
  427. /*
  428. **
  429. ** BeginIO
  430. **
  431. ** This is the dispatch point for the driver's incoming IORequests.
  432. **
  433. */
  434.  
  435. #define SLIP_IMMEDIATES 0L
  436.  
  437. VOID ASM DevBeginIO(REG(a1) struct IOSana2Req *ios2)
  438. {
  439.     ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  440.  
  441.     if(ios2->ios2_Req.io_Command < S2_END)
  442.     {
  443.         if((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)
  444.         {
  445.             PerformIO(ios2);
  446.         }
  447.         else
  448.         {
  449.             ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  450.             PutMsg((struct MsgPort *)ios2->ios2_Req.io_Unit,(struct Message *)ios2);
  451.         }
  452.     }
  453.     else
  454.     {
  455.         ios2->ios2_Req.io_Error = IOERR_NOCMD;
  456.         TermIO(ios2);
  457.     }
  458. }
  459.  
  460. /*
  461. ** This routine is used to dispatch an IO request either from BeginIO
  462. ** or from the Unit process.
  463. */
  464. VOID PerformIO(struct IOSana2Req *ios2)
  465. {
  466.     struct SLIPDevUnit *sdu;
  467.  
  468.     sdu = (struct SLIPDevUnit *)ios2->ios2_Req.io_Unit;
  469.  
  470.     ios2->ios2_Req.io_Error = 0;
  471.  
  472.     switch(ios2->ios2_Req.io_Command)
  473.     {
  474.         case CMD_READ:              ReadPacket(sdu,ios2);
  475.                                     break;
  476.  
  477.         case CMD_WRITE:             WritePacket(sdu,ios2);
  478.                                     break;
  479.  
  480.         case S2_DEVICEQUERY:        DeviceQuery(sdu,ios2);
  481.                                     break;
  482.  
  483.         case S2_GETSTATIONADDRESS:  GetStationAddress(sdu,ios2);
  484.                                     break;
  485.  
  486.         case S2_CONFIGINTERFACE:    ConfigInterface(sdu,ios2);
  487.                                     break;
  488.  
  489.         case S2_ADDMULTICASTADDRESS:
  490.         case S2_DELMULTICASTADDRESS:
  491.         case S2_MULTICAST:          ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  492.                                     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  493.                                     TermIO(ios2);
  494.                                     break;
  495.  
  496.         case S2_BROADCAST:          WritePacket(sdu,ios2);
  497.                                     break;
  498.  
  499.         case S2_TRACKTYPE:          TrackType(sdu,ios2);
  500.                                     break;
  501.  
  502.         case S2_UNTRACKTYPE:        UnTrackType(sdu,ios2);
  503.                                     break;
  504.  
  505.         case S2_GETTYPESTATS:       GetTypeStats(sdu,ios2);
  506.                                     break;
  507.  
  508.         case S2_GETSPECIALSTATS:    GetSpecialStats(sdu,ios2);
  509.                                     break;
  510.  
  511.         case S2_GETGLOBALSTATS:     GetGlobalStats(sdu,ios2);
  512.                                     break;
  513.  
  514.         case S2_ONEVENT:            OnEvent(sdu,ios2);
  515.                                     break;
  516.  
  517.         case S2_READORPHAN:         ReadOrphan(sdu,ios2);
  518.                                     break;
  519.  
  520.         case S2_ONLINE:             Online(sdu,ios2);
  521.                                     break;
  522.  
  523.         case S2_OFFLINE:            Offline(sdu,ios2);
  524.                                     break;
  525.  
  526.         default:                    ios2->ios2_Req.io_Error = IOERR_NOCMD;
  527.                                     TermIO(ios2);
  528.                                     break;
  529.     }
  530. }
  531.  
  532. /*
  533. ** This function returns any device specific statistics that
  534. ** we may have.  Unfortunately, we don't have and SLIP specific
  535. ** statistics.
  536. */
  537. VOID GetSpecialStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  538. {
  539.     struct Sana2SpecialStatHeader *stats;
  540.  
  541.     stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
  542.  
  543.     stats->RecordCountSupplied = 0;
  544.     TermIO(ios2);
  545. }
  546.  
  547. /*
  548. ** This function returns the global statistics for the
  549. ** slip device.
  550. */
  551. VOID GetGlobalStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  552. {
  553.     struct Sana2DeviceStats *stats;
  554.  
  555.     stats = (struct Sana2DeviceStats *)ios2->ios2_StatData;
  556.  
  557.     stats->PacketsReceived    = sdu->sdu_Stats.PacketsReceived;
  558.     stats->PacketsSent        = sdu->sdu_Stats.PacketsSent;
  559.     stats->BadData        = sdu->sdu_Stats.BadData;
  560.     stats->Overruns        = sdu->sdu_Stats.Overruns;
  561.     stats->UnknownTypesReceived = sdu->sdu_Stats.UnknownTypesReceived;
  562.     stats->Reconfigurations    = sdu->sdu_Stats.Reconfigurations;
  563.     stats->LastStart.tv_secs    = sdu->sdu_Stats.LastStart.tv_secs;
  564.     stats->LastStart.tv_micro    = sdu->sdu_Stats.LastStart.tv_secs;
  565.  
  566.     ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
  567.     ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  568.     TermIO(ios2);
  569. }
  570.  
  571. /*
  572. ** This function returns statistics for a specific
  573. ** type of packet that is being tracked.  Unfortunately,
  574. ** SLIP can't differentiate between different packet
  575. ** types, which makes packet type tracking essentially
  576. ** useless as the numbers would essentially be the same
  577. ** as those found via S2_GETGLOBALSTATS.
  578. **
  579. ** Just to be thourough, I have arbitrarily picked
  580. ** the packet type for SLIP IP packets to be 2048, the
  581. ** same as tha used for Ethernet.  This will at least
  582. ** allow you to track IP packets.
  583. */
  584. VOID GetTypeStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  585. {
  586.     struct Sana2PacketTypeStats *stats;
  587.     struct SuperS2PTStats *sstats;
  588.  
  589.     ObtainSemaphore(&sdu->sdu_ListLock);
  590.  
  591.     stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData;
  592.     sstats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  593.  
  594.     while(sstats->ss_Node.mln_Succ)
  595.     {
  596.         if(ios2->ios2_PacketType == sstats->ss_PType)
  597.         {
  598.             stats->PacketsSent = sstats->ss_Stats.PacketsSent;
  599.             stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
  600.             stats->BytesSent = sstats->ss_Stats.BytesSent;
  601.             stats->BytesReceived = sstats->ss_Stats.BytesReceived;
  602.             stats->PacketsDropped = sstats->ss_Stats.PacketsDropped;
  603.         break;
  604.     }
  605.     sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
  606.     }
  607.     ReleaseSemaphore(&sdu->sdu_ListLock);
  608.     if(!sstats->ss_Node.mln_Succ)
  609.     {
  610.     ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  611.     ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  612.     }
  613.     TermIO(ios2);
  614. }
  615.  
  616. /*
  617. ** This function adds a packet type to the list
  618. ** of those that are being tracked.
  619. */
  620. VOID TrackType(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  621. {
  622.     struct SuperS2PTStats *stats;
  623.  
  624.     ObtainSemaphore(&sdu->sdu_ListLock);
  625.  
  626.     stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  627.  
  628.     while(stats->ss_Node.mln_Succ)
  629.     {
  630.         if(ios2->ios2_PacketType == stats->ss_PType)
  631.         {
  632.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  633.         ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
  634.     }
  635.     stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  636.     }
  637.     if(!stats->ss_Node.mln_Succ)
  638.     {
  639.         if(stats = AllocMem(sizeof(struct SuperS2PTStats),MEMF_CLEAR|MEMF_PUBLIC))
  640.         {
  641.             if(ios2->ios2_PacketType == 2048)
  642.                 sdu->sdu_IPTrack = stats;
  643.             AddTail((struct List *)&sdu->sdu_Track,(struct Node *)stats);
  644.         }
  645.     }
  646.     ReleaseSemaphore(&sdu->sdu_ListLock);
  647.  
  648.     TermIO(ios2);
  649. }
  650.  
  651. /*
  652. ** This function removes a packet type from the
  653. ** list of those that are being tracked.
  654. */
  655. VOID UnTrackType(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  656. {
  657.     struct SuperS2PTStats *stats;
  658.     struct SuperS2PTStats *stats_next;
  659.  
  660.     ObtainSemaphore(&sdu->sdu_ListLock);
  661.  
  662.     stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
  663.  
  664.     while(stats->ss_Node.mln_Succ)
  665.     {
  666.         stats_next = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
  667.         if(ios2->ios2_PacketType == stats->ss_PType)
  668.         {
  669.             if(ios2->ios2_PacketType == 2048)
  670.                 sdu->sdu_IPTrack = NULL;
  671.             Remove((struct Node *)stats);
  672.             FreeMem(stats,sizeof(struct SuperS2PTStats));
  673.             stats = NULL;
  674.         break;
  675.     }
  676.     stats = stats_next;
  677.     }
  678.     if(stats)
  679.     {
  680.     ios2->ios2_Req.io_Error    = S2ERR_BAD_STATE;
  681.     ios2->ios2_WireError = S2WERR_NOT_TRACKED;
  682.     }
  683.     ReleaseSemaphore(&sdu->sdu_ListLock);
  684.  
  685.     TermIO(ios2);
  686. }
  687.  
  688. /*
  689. ** This function is called whenever we receive a packet
  690. ** from the serial device driver.
  691. **
  692. */
  693. VOID PacketReceived(struct SLIPDevUnit *sdu, ULONG length)
  694. {
  695.     sdu->sdu_Stats.PacketsReceived++;
  696.  
  697.     if(sdu->sdu_IPTrack)
  698.     {
  699.         sdu->sdu_IPTrack->ss_Stats.PacketsReceived++;
  700.         sdu->sdu_IPTrack->ss_Stats.BytesReceived+=length;
  701.     }
  702. }
  703.  
  704. /*
  705. ** This function is called whenever a packet is
  706. ** sent to the serial device driver.
  707. */
  708. VOID PacketSent(struct SLIPDevUnit *sdu, ULONG length)
  709. {
  710.     sdu->sdu_Stats.PacketsSent++;
  711.  
  712.     if(sdu->sdu_IPTrack)
  713.     {
  714.         sdu->sdu_IPTrack->ss_Stats.PacketsSent++;
  715.         sdu->sdu_IPTrack->ss_Stats.BytesSent+=length;
  716.     }
  717. }
  718.  
  719. /*
  720. ** This function is called whenever a packet that
  721. ** is too large is received.
  722. */
  723. VOID PacketOverrun(struct SLIPDevUnit *sdu)
  724. {
  725.     sdu->sdu_Stats.Overruns++;
  726.     DoEvent(sdu, S2EVENT_RX);
  727. }
  728.  
  729. /*
  730. ** This function is called whenever a packet with
  731. ** garbage data is encountered.
  732. */
  733. VOID ReceivedGarbage(struct SLIPDevUnit *sdu)
  734. {
  735.     sdu->sdu_Stats.BadData++;
  736.     DoEvent(sdu, S2EVENT_RX);
  737. }
  738.  
  739. /*
  740. ** This function is called whenever a packet
  741. ** is dropped by the SLIP driver.
  742. */
  743. VOID PacketDropped(struct SLIPDevUnit *sdu)
  744. {
  745.     if(sdu->sdu_IPTrack)
  746.     {
  747.         sdu->sdu_IPTrack->ss_Stats.PacketsDropped++;
  748.     }
  749. }
  750.  
  751. /*
  752. ** This function is used to return an IO request
  753. ** back to the sender.
  754. */
  755. VOID TermIO(struct IOSana2Req *ios2)
  756. {
  757.     if(!(ios2->ios2_Req.io_Flags & IOF_QUICK))
  758.         ReplyMsg((struct Message *)ios2);
  759. }
  760.  
  761. /*
  762. ** The device AbortIO() entry point.
  763. **
  764. ** A1 - The IO request to be aborted.
  765. ** A3 - The unit pointer
  766. ** A6 - The device base.
  767. */
  768. ULONG ASM DevAbortIO(REG(a1) struct IOSana2Req *ios2, REG(a3) struct SLIPDevUnit *sdu)
  769. {
  770.     ULONG result = 0L;
  771.  
  772.     ObtainSemaphore(&sdu->sdu_ListLock);
  773.     if(ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG)
  774.     {
  775.         switch(ios2->ios2_Req.io_Command)
  776.         {
  777.             case CMD_READ:    result=AbortReq(&sdu->sdu_Rx,ios2);
  778.                     break;
  779.  
  780.             case CMD_WRITE: result=AbortReq(&sdu->sdu_Tx,ios2);
  781.                     break;
  782.  
  783.             case S2_READORPHAN:    result=AbortReq(&sdu->sdu_RxOrph,ios2);
  784.                         break;
  785.  
  786.             case S2_ONEVENT:    result=AbortReq(&sdu->sdu_Events,ios2);
  787.                         break;
  788.  
  789.             default:        result=IOERR_NOCMD;
  790.                         break;
  791.     }
  792.     }
  793.     ReleaseSemaphore(&sdu->sdu_ListLock);
  794.     return(result);
  795. }
  796.  
  797. /*
  798. ** This funcion is used to locate an IO request in a linked
  799. ** list and abort it if found.
  800. */
  801. ULONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
  802. {
  803.     struct Node *node, *next;
  804.     ULONG result=IOERR_NOCMD;
  805.  
  806.     node = (struct Node *)minlist->mlh_Head;
  807.  
  808.     while(node->ln_Succ)
  809.     {
  810.         next = node->ln_Succ;
  811.  
  812.         if(node == (struct Node *)ios2)
  813.         {
  814.             Remove((struct Node *)ios2);
  815.             ios2->ios2_Req.io_Error = IOERR_ABORTED;
  816.             TermIO(ios2);
  817.         result = 0;
  818.     }
  819.     node = next;
  820.     }
  821.     return(result);
  822. }
  823.  
  824. /*
  825. ** This function handles S2_CONFIGINTERFACE commands.
  826. */
  827. VOID ConfigInterface(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  828. {
  829.  
  830.     /* Note: we may only be configured once. */
  831.     if(!(sdu->sdu_State & SLIPUF_CONFIG))
  832.     {
  833.         if(OpenSerial(sdu))
  834.         {
  835.             CopyMem(&sdu->sdu_StAddr,&ios2->ios2_SrcAddr,4);
  836.             sdu->sdu_State |= SLIPUF_CONFIG;
  837.         }
  838.     }
  839.     else
  840.     {
  841.         /* Sorry, we're already configured. */
  842.         ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
  843.         ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
  844.     }
  845.     TermIO(ios2);
  846. }
  847.  
  848. /*
  849. ** This function handles S2_GETSTATIONADDRESS commands.
  850. **
  851. ** We don't really have a hardware address, so we will
  852. ** just clear the source address field.
  853. */
  854.  
  855. VOID GetStationAddress(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  856. {
  857.     UBYTE i;
  858.  
  859.     for(i=0; i< SANA2_MAX_ADDR_BYTES; i++)
  860.         ios2->ios2_SrcAddr[i]=0;
  861.  
  862.     TermIO(ios2);
  863. }
  864.  
  865. /*
  866. ** This function handles S2_DEVICEQUERY comands.
  867. */
  868. VOID DeviceQuery(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  869. {
  870.     struct Sana2DeviceQuery *sdq;
  871.  
  872.     sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
  873.  
  874.     sdq->AddrFieldSize = 32;            /* 32-bit IP address */
  875.     sdq->MTU = SLIP_MTU;            /* 1006 byte max */
  876.     sdq->BPS = sdu->sdu_BaudRate;
  877.     sdq->HardwareType = S2WireType_SLIP;
  878.  
  879.     sdq->SizeSupplied = 14;
  880.     TermIO(ios2);
  881. }
  882.  
  883. /*
  884. ** This function is used for handling CMD_WRITE
  885. ** commands.
  886. */
  887. VOID WritePacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  888. {
  889.  
  890.     /* Make sure that we are online. */
  891.     if(sdu->sdu_State & SLIPUF_ONLINE)
  892.     {
  893.     /* Make sure it's a legal length. */
  894.         if(ios2->ios2_DataLength <= SLIP_MTU)
  895.         {
  896.             /* See if our serial CMD_WRITE command is busy.  If it's not, send
  897.                the IO request to SendPacket. */
  898.             if(CheckIO((struct IORequest *)sdu->sdu_SerTx))
  899.             {
  900.                 WaitIO((struct IORequest *)sdu->sdu_SerTx);
  901.                 SendPacket(sdu, ios2);
  902.             }
  903.             else
  904.             {
  905.                 /* We'll have to queue the packet for later...*/
  906.                 ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
  907.                 ObtainSemaphore(&sdu->sdu_ListLock);
  908.                 AddTail((struct List *)&sdu->sdu_Tx,(struct Node *)ios2);
  909.                 ReleaseSemaphore(&sdu->sdu_ListLock);
  910.             }
  911.         }
  912.         else
  913.         {
  914.             /* Sorry, the packet is too long! */
  915.             ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
  916.             ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  917.             TermIO(ios2);
  918.             DoEvent(sdu,S2EVENT_TX);
  919.         }
  920.     }
  921.     else
  922.     {
  923.         /* Sorry, we're offline */
  924.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  925.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  926.         TermIO(ios2);
  927.     }
  928. }
  929.  
  930. VOID SendPacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  931. {
  932.     struct IOExtSer *ioser;
  933.     struct BufferManagement *bm;
  934.     ULONG framelength;
  935.  
  936.     bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
  937.  
  938.     /* Copy the data out of the packet into our temporary buffer. */
  939.     if((*bm->bm_CopyFromBuffer)(sdu->sdu_TxBuff,ios2->ios2_Data,ios2->ios2_DataLength))
  940.     {
  941.         PacketSent(sdu,ios2->ios2_DataLength);
  942.  
  943.     /* Encode the packet in SLIP format */
  944.         framelength=EncodeSLIP(sdu->sdu_TxBuff,sdu->sdu_TxSLIP,ios2->ios2_DataLength);
  945.  
  946.         ioser = sdu->sdu_SerTx;
  947.         ioser->IOSer.io_Data = sdu->sdu_TxSLIP;
  948.         ioser->IOSer.io_Length = framelength;
  949.         ioser->IOSer.io_Command = CMD_WRITE;
  950.         ioser->IOSer.io_Error = 0;
  951.         ioser->IOSer.io_Message.mn_Node.ln_Type = 0;
  952.  
  953.         /* Send the packet to the serial device driver */
  954.         SendIO((struct IORequest *)ioser);
  955.     }
  956.     else
  957.     {
  958.         /* Something went wrong...*/
  959.         ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  960.         ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  961.         DoEvent(sdu,S2EVENT_BUFF);
  962.     }
  963.     TermIO(ios2);
  964. }
  965.  
  966. /*
  967. ** This routine encodes a packet in SLIP format.
  968. **
  969. ** The format is quite simple.
  970. **
  971. ** SLIP Encoding:
  972. **
  973. ** SLIP_ESC     -> SLIP_ESC SLIP_ESC_ESC
  974. ** SLIP_END     -> SLIP_ESC SLIP_ESC_END
  975. **
  976. ** The packet is preceded and terminated with a SLIP_END as prescribed by
  977. ** rfc 1055.
  978. **
  979. */
  980. ULONG EncodeSLIP(UBYTE *source, UBYTE *dest, ULONG length)
  981. {
  982.     UBYTE ch;
  983.     UBYTE *current;
  984.  
  985.     current = dest;
  986.  
  987.     *current = SLIP_END;
  988.     current++;
  989.  
  990.     while(length--)
  991.     {
  992.         ch = *source;
  993.         source++;
  994.  
  995.         if(ch == SLIP_ESC)
  996.         {
  997.             *current = SLIP_ESC;
  998.             current++;
  999.             ch = SLIP_ESC_ESC;
  1000.         }
  1001.         else if(ch == SLIP_END)
  1002.         {
  1003.             *current = SLIP_ESC;
  1004.             current ++;
  1005.             ch = SLIP_ESC_END;
  1006.         }
  1007.     *current = ch;
  1008.     current++;
  1009.     }
  1010.     *current = SLIP_END;
  1011.     current++;
  1012.  
  1013.     return((ULONG)(current - dest));
  1014. }
  1015.  
  1016. /*
  1017. ** This routine handles CMD_READ commands.  We
  1018. ** always queue these unless we're offline.
  1019. */
  1020. VOID ReadPacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  1021. {
  1022.  
  1023.     if(sdu->sdu_State & SLIPUF_ONLINE)
  1024.     {
  1025.         /* Queue it... */
  1026.         ObtainSemaphore(&sdu->sdu_ListLock);
  1027.         AddTail((struct List *)&sdu->sdu_Rx,(struct Node *)ios2);
  1028.         ReleaseSemaphore(&sdu->sdu_ListLock);
  1029.     }
  1030.     else
  1031.     {
  1032.         /* Sorry, we're offline */
  1033.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1034.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1035.         TermIO(ios2);
  1036.     }
  1037. }
  1038.  
  1039. /*
  1040. ** This routine handles CMD_READORPHAN commands.  We
  1041. ** always queue these unless we're offline.
  1042. **
  1043. ** Note: These IO requests will never get satisfied.
  1044. **       Since SLIP doesn't contain packet type information,
  1045. **     there is no way to identify what type of packets
  1046. **     are being received or sent.  Thus, we simply ignore
  1047. **     the packet type and *assume* that the packets are
  1048. **     IP packets.
  1049. */
  1050. VOID ReadOrphan(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  1051. {
  1052.  
  1053.     if(sdu->sdu_State & SLIPUF_ONLINE)
  1054.     {
  1055.         /* Queue it...*/
  1056.         ObtainSemaphore(&sdu->sdu_ListLock);
  1057.         AddTail((struct List *)&sdu->sdu_RxOrph,(struct Node *)ios2);
  1058.         ReleaseSemaphore(&sdu->sdu_ListLock);
  1059.     }
  1060.     else
  1061.     {
  1062.         /* Sorry, we're offline */
  1063.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1064.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1065.         TermIO(ios2);
  1066.     }
  1067. }
  1068.  
  1069. /*
  1070. ** This routine initializes our IO requests and buffers
  1071. ** for serial i/o and SLIP encoding/decoding.
  1072. */
  1073. BOOL InitSerial(struct SLIPDevUnit *sdu)
  1074. {
  1075.     ULONG *clr;
  1076.     BOOL status = FALSE;
  1077.  
  1078.     for(clr = (ULONG *) &sdu->sdu_SerRx; clr <= (ULONG *) &sdu->sdu_TxSLIP; clr++)
  1079.         *clr = 0L;
  1080.  
  1081.     if(sdu->sdu_TxPort = CreateMsgPort())
  1082.     {
  1083.         if(sdu->sdu_SerTx = CreateIORequest(sdu->sdu_TxPort,sizeof(struct IOExtSer)))
  1084.         {
  1085.             if(sdu->sdu_RxPort = CreateMsgPort())
  1086.             {
  1087.                 if(sdu->sdu_SerRx = CreateIORequest(sdu->sdu_RxPort,sizeof(struct IOExtSer)))
  1088.                 {
  1089.                     if(sdu->sdu_TxBuff = AllocMem((SLIP_MTU + 128) * 2,MEMF_CLEAR|MEMF_PUBLIC))
  1090.                     {
  1091.                         sdu->sdu_RxBuff = sdu->sdu_TxBuff + SLIP_MTU + 128;
  1092.                         sdu->sdu_RxBuffPtr = sdu->sdu_RxBuff;
  1093.  
  1094.                         if(sdu->sdu_TxSLIP = AllocMem((SLIP_MTU*2 + 128) * 2,MEMF_CLEAR|MEMF_PUBLIC))
  1095.                         {
  1096.                             sdu->sdu_RxSLIP = sdu->sdu_TxSLIP + SLIP_MTU*2 + 128;
  1097.                             {
  1098.                                 status = TRUE;
  1099.                             }
  1100.                         }
  1101.                     }
  1102.                 }
  1103.             }
  1104.         }
  1105.     }
  1106.     if(!status)
  1107.         DeinitSerial(sdu);
  1108.     return(status);
  1109. }
  1110.  
  1111. /*
  1112. ** This routine cleans up our serial i/o requests
  1113. ** and misc. buffers.
  1114. */
  1115. VOID DeinitSerial(struct SLIPDevUnit *sdu)
  1116. {
  1117.     if(sdu->sdu_SerTx)
  1118.         DeleteIORequest(sdu->sdu_SerTx);
  1119.  
  1120.     if(sdu->sdu_TxPort)
  1121.         DeleteMsgPort(sdu->sdu_TxPort);
  1122.  
  1123.     if(sdu->sdu_SerRx)
  1124.         DeleteIORequest(sdu->sdu_SerRx);
  1125.  
  1126.     if(sdu->sdu_RxPort)
  1127.         DeleteMsgPort(sdu->sdu_RxPort);
  1128.  
  1129.     if(sdu->sdu_TxBuff)
  1130.         FreeMem(sdu->sdu_TxBuff,(SLIP_MTU + 128) * 2);
  1131.  
  1132.     if(sdu->sdu_TxSLIP)
  1133.         FreeMem(sdu->sdu_TxSLIP,(SLIP_MTU*2 + 128) * 2);
  1134. }
  1135.  
  1136. /*
  1137. ** This routine handles S2_ONEVNET commands.
  1138. */
  1139. VOID OnEvent(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  1140. {
  1141.  
  1142.     switch(ios2->ios2_WireError)
  1143.     {
  1144.         /* Special case.  We may already be online, in which
  1145.            case the IO request should return immediately. Otherwise
  1146.            we queue it for later. */
  1147.  
  1148.         case S2EVENT_ONLINE:
  1149.                     if(sdu->sdu_State & SLIPUF_ONLINE)
  1150.                         TermIO(ios2);
  1151.                     else
  1152.                     {
  1153.                         ObtainSemaphore(&sdu->sdu_ListLock);
  1154.                         AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  1155.                         ReleaseSemaphore(&sdu->sdu_ListLock);
  1156.                     }
  1157.                     break;
  1158.  
  1159.     /* Same as with S2EVENT_ONLINE, but the opposite
  1160.        happens. */
  1161.     case S2EVENT_OFFLINE:
  1162.                 if(sdu->sdu_State & SLIPUF_ONLINE)
  1163.                 {
  1164.                     ObtainSemaphore(&sdu->sdu_ListLock);
  1165.                         AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  1166.                         ReleaseSemaphore(&sdu->sdu_ListLock);
  1167.                     }
  1168.                 else
  1169.                         TermIO(ios2);
  1170.                 break;
  1171.  
  1172.     /* Just queue everything else. */
  1173.     default:
  1174.                     ObtainSemaphore(&sdu->sdu_ListLock);
  1175.                     AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
  1176.                     ReleaseSemaphore(&sdu->sdu_ListLock);
  1177.                 break;
  1178.     }
  1179. }
  1180.  
  1181. /*
  1182. ** This routine opens the serial device driver and attempts to bring
  1183. ** the device online.
  1184. */
  1185. BOOL OpenSerial(struct SLIPDevUnit *sdu)
  1186. {
  1187.     BOOL status = TRUE;
  1188.     ULONG odflags = 0;
  1189.  
  1190.     sdu->sdu_SerRx->IOSer.io_Device = NULL;
  1191.  
  1192.     if(sdu->sdu_State & SLIPUF_7WIRE)
  1193.         odflags = SERF_7WIRE;
  1194.  
  1195.     if(!OpenDevice(sdu->sdu_SerDevName,sdu->sdu_SerUnitNum,(struct IORequest *)sdu->sdu_SerTx,odflags))
  1196.     {
  1197.         /* Set up our serial parameters */
  1198.         sdu->sdu_SerRx->IOSer.io_Device = sdu->sdu_SerTx->IOSer.io_Device;
  1199.         sdu->sdu_SerRx->IOSer.io_Unit = sdu->sdu_SerTx->IOSer.io_Unit;
  1200.  
  1201.         sdu->sdu_SerTx->IOSer.io_Command = SDCMD_SETPARAMS;
  1202.         sdu->sdu_SerTx->io_Baud = sdu->sdu_BaudRate;
  1203.         sdu->sdu_SerTx->io_RBufLen = 16384L;
  1204.         sdu->sdu_SerTx->io_ReadLen = 8;
  1205.         sdu->sdu_SerTx->io_WriteLen = 8;
  1206.         sdu->sdu_SerTx->io_StopBits = 1;
  1207.         sdu->sdu_SerTx->io_SerFlags = SERF_XDISABLED|SERF_RAD_BOOGIE;
  1208.  
  1209.         if(!DoIO((struct IORequest *)sdu->sdu_SerTx))
  1210.         {
  1211.             /* Assume we're now online */
  1212.             sdu->sdu_State |= SLIPUF_ONLINE;
  1213.  
  1214.             /* Are we checking for serial detect? */
  1215.             if(sdu->sdu_State & SLIPUF_CD)
  1216.             {
  1217.                 sdu->sdu_SerTx->IOSer.io_Command = SDCMD_QUERY;
  1218.                 if(!DoIO((struct IORequest *)sdu->sdu_SerTx))
  1219.                 {
  1220.                     if(sdu->sdu_SerTx->io_Status & (1<<5))
  1221.                     {
  1222.                         /* Sorry, no carrier, shut down the serial driver
  1223.                            and set our state to offline. */
  1224.                         CloseDevice((struct IORequest *)sdu->sdu_SerTx);
  1225.                         sdu->sdu_State &= ~SLIPUF_ONLINE;
  1226.                     }
  1227.                 }
  1228.                 else
  1229.                     status = FALSE;
  1230.             }
  1231.             if(status)
  1232.             {
  1233.                 /* Queue up the initial CMD_READ command for the
  1234.                    serial driver. */
  1235.                 sdu->sdu_SerRx->IOSer.io_Command = CMD_READ;
  1236.                 sdu->sdu_SerRx->IOSer.io_Length = 1;
  1237.                 sdu->sdu_SerRx->IOSer.io_Data = sdu->sdu_RxSLIP;
  1238.                 SendIO((struct IORequest *)sdu->sdu_SerRx);
  1239.             }
  1240.         }
  1241.         else
  1242.             status = FALSE;
  1243.  
  1244.         if(!status)
  1245.             CloseDevice((struct IORequest *)sdu->sdu_SerTx);
  1246.     }
  1247.     else
  1248.     {
  1249.         struct Library *IntuitionBase;
  1250.         struct EasyStruct es;
  1251.         ULONG args[2];
  1252.         args[0]=(ULONG)sdu->sdu_SerDevName;
  1253.         args[1]=(ULONG)sdu->sdu_SerUnitNum;
  1254.         if(IntuitionBase = OpenLibrary("intuition.library",37L))
  1255.         {
  1256.             es.es_StructSize=sizeof(struct EasyStruct);
  1257.             es.es_Flags=0;
  1258.             es.es_Title="Slip.device";
  1259.             es.es_TextFormat="Couldn't open %s unit %ld.";
  1260.             es.es_GadgetFormat="Okay";
  1261.             EasyRequestArgs(NULL, &es, 0, (APTR)args);
  1262.             CloseLibrary(IntuitionBase);
  1263.         }
  1264.         status = FALSE;
  1265.     }
  1266.     if(sdu->sdu_State & SLIPUF_ONLINE)
  1267.         MarkTimeOnline(sdu);
  1268.  
  1269.     return(status);
  1270. }
  1271.  
  1272. /*
  1273. ** This routine gets the current system time and stores
  1274. ** it in our global statistics structure.
  1275. */
  1276.  
  1277. VOID MarkTimeOnline(struct SLIPDevUnit *sdu)
  1278. {
  1279.     register struct Library *TimerBase;
  1280.     struct timerequest *treq;
  1281.  
  1282.     if(treq = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
  1283.     {
  1284.         if(!OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)treq,0L))
  1285.         {
  1286.             TimerBase = (struct Library *)treq->tr_node.io_Device;
  1287.             GetSysTime(&sdu->sdu_Stats.LastStart);
  1288.             CloseDevice((struct IORequest *)treq);
  1289.         }
  1290.         FreeMem(treq,sizeof(struct timerequest));
  1291.     }
  1292. }
  1293.  
  1294. /*
  1295. ** This routine aborts any pending activity with the serial
  1296. ** device driver and then brings the slip driver offline.
  1297. */
  1298. VOID CloseSerial(struct SLIPDevUnit *sdu)
  1299. {
  1300.     AbortIO((struct IORequest *)sdu->sdu_SerRx);
  1301.     WaitIO((struct IORequest *)sdu->sdu_SerRx);
  1302.  
  1303.     while(GetMsg(sdu->sdu_RxPort));
  1304.  
  1305.     AbortIO((struct IORequest *)sdu->sdu_SerTx);
  1306.     WaitIO((struct IORequest *)sdu->sdu_SerTx);
  1307.  
  1308.     while(GetMsg(sdu->sdu_TxPort));
  1309.  
  1310.     CloseDevice((struct IORequest *)sdu->sdu_SerRx);
  1311.  
  1312.     sdu->sdu_State &= ~SLIPUF_ONLINE;
  1313. }
  1314.  
  1315. /*
  1316. ** This routime handles CMD_ONLINE commands.
  1317. */
  1318. VOID Online(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  1319. {
  1320.  
  1321.     if(!(sdu->sdu_State & SLIPUF_ONLINE))
  1322.     {
  1323.         /* We're offline. Try to go online. */
  1324.         if(OpenSerial(sdu))
  1325.         {
  1326.             if(sdu->sdu_State & SLIPUF_ONLINE)
  1327.             {
  1328.                 /* In case someone wants to know...*/
  1329.                 DoEvent(sdu, S2EVENT_ONLINE);
  1330.             }
  1331.             else
  1332.             {
  1333.                 /* Sorry, the attempt to go online failed. */
  1334.                 ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1335.                 ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1336.             }
  1337.         }
  1338.         else
  1339.         {
  1340.             /* A general problem occured. */
  1341.             ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
  1342.             ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
  1343.         }
  1344.     }
  1345.     TermIO(ios2);
  1346. }
  1347.  
  1348. /*
  1349. ** This routine handles CMD_OFFLINE commands.
  1350. */
  1351. VOID Offline(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
  1352. {
  1353.     TermIO(ios2);
  1354.  
  1355.     if(sdu->sdu_State & SLIPUF_ONLINE)
  1356.     {
  1357.         /* We're online, so shut everything down. */
  1358.     CloseSerial(sdu);
  1359.     DoOffline(sdu);
  1360.     DoEvent(sdu,S2EVENT_OFFLINE);
  1361.     }
  1362. }
  1363.  
  1364. /*
  1365. ** This routine is called whenever an "important"
  1366. ** SANA-II event occurs.
  1367. */
  1368. VOID DoEvent(struct SLIPDevUnit *sdu, ULONG event)
  1369. {
  1370.     struct IOSana2Req *ios2;
  1371.     struct IOSana2Req *ios2_next;
  1372.  
  1373.     ObtainSemaphore(&sdu->sdu_ListLock);
  1374.  
  1375.     ios2 = (struct IOSana2Req *)sdu->sdu_Events.mlh_Head;
  1376.  
  1377.     while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
  1378.     {
  1379.         ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
  1380.  
  1381.         /* Is this the event they are looking for? */
  1382.         if(ios2->ios2_WireError == event)
  1383.         {
  1384.             Remove((struct Node *)ios2);
  1385.             TermIO(ios2);
  1386.         }
  1387.         ios2 = ios2_next;
  1388.     }
  1389.     ReleaseSemaphore(&sdu->sdu_ListLock);
  1390. }
  1391.  
  1392. /*
  1393. ** This routine is called whenever the device needs to
  1394. ** be taken offline.  We return any pending CMD_READ's
  1395. ** or CMD_WRITE's to their senders.
  1396. */
  1397. VOID DoOffline(struct SLIPDevUnit *sdu)
  1398. {
  1399.     struct IOSana2Req *ios2;
  1400.  
  1401.     ObtainSemaphore(&sdu->sdu_ListLock);
  1402.  
  1403.     while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx))
  1404.     {
  1405.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1406.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1407.         TermIO(ios2);
  1408.     }
  1409.  
  1410.     while(ios2 = (struct IOSana2Req *)RemHead((struct Lust *)&sdu->sdu_Tx))
  1411.     {
  1412.         ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
  1413.         ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
  1414.         TermIO(ios2);
  1415.     }
  1416.     ReleaseSemaphore(&sdu->sdu_ListLock);
  1417. }
  1418.  
  1419. /*
  1420. ** This routine is called whenever a CMD_WRITE request
  1421. ** has returned from the serial driver.
  1422. */
  1423. VOID ServiceTxPort(struct SLIPDevUnit *sdu)
  1424. {
  1425.     struct IOSana2Req *ios2;
  1426.  
  1427.     /* See if we have any pending CMD_WRITE requests. */
  1428.     if(sdu->sdu_State & SLIPUF_ONLINE)
  1429.     {
  1430.         ObtainSemaphore(&sdu->sdu_ListLock);
  1431.         ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx);
  1432.         ReleaseSemaphore(&sdu->sdu_ListLock);
  1433.  
  1434.         if(ios2)
  1435.         {
  1436.             SendPacket(sdu, ios2);
  1437.             sdu->sdu_NoMore = 1;
  1438.         }
  1439.     }
  1440.     else
  1441.         sdu->sdu_NoMore = 1;
  1442. }
  1443.  
  1444. /*
  1445. ** This routine is called whenever a CMD_READ request
  1446. ** returns from the serial driver.  It decodes the
  1447. ** packet data and tries to build complete packets.
  1448. */
  1449. VOID DoSerial(struct SLIPDevUnit *sdu, struct IOExtSer *ioSer)
  1450. {
  1451.     UBYTE *rx_ptr,*packet_ptr;
  1452.     UBYTE rx_byte, packet_byte;
  1453.     ULONG length;
  1454.  
  1455.     packet_ptr = sdu->sdu_RxBuffPtr;
  1456.     rx_ptr = sdu->sdu_RxSLIP;
  1457.  
  1458.     length = ioSer->IOSer.io_Length;
  1459.  
  1460.     while(length--)
  1461.     {
  1462.         rx_byte = packet_byte = *rx_ptr;
  1463.         rx_ptr++;
  1464.  
  1465.     /* Handle SLIP packet decoding...*/
  1466.         if(sdu->sdu_Escape)
  1467.         {
  1468.             if(rx_byte == SLIP_ESC_ESC)
  1469.                 packet_byte = SLIP_ESC;
  1470.             else if(rx_byte = SLIP_ESC_END)
  1471.                 packet_byte = SLIP_END;
  1472.             else
  1473.                 ReceivedGarbage(sdu);        /* This packet may be hosed */
  1474.  
  1475.             sdu->sdu_Escape = FALSE;
  1476.         }
  1477.         else if(rx_byte == SLIP_ESC)
  1478.         {
  1479.             sdu->sdu_Escape = TRUE;
  1480.             continue;
  1481.         }
  1482.         else if(rx_byte == SLIP_END)
  1483.         {
  1484.             GotPacket(sdu,(ULONG)(packet_ptr - sdu->sdu_RxBuff));
  1485.             packet_ptr = sdu->sdu_RxBuff;
  1486.             continue;
  1487.         }
  1488.         *packet_ptr = packet_byte;
  1489.         packet_ptr++;
  1490.  
  1491.         if(((ULONG)(packet_ptr - sdu->sdu_RxBuff)) > SLIP_MTU)
  1492.         {
  1493.             packet_ptr = sdu->sdu_RxBuff;
  1494.             PacketOverrun(sdu);
  1495.         }
  1496.     }
  1497.     sdu->sdu_RxBuffPtr = packet_ptr;
  1498.  
  1499.     /* Queue up another CMD_READ request...*/
  1500.     QueueSerRequest(sdu);
  1501. }
  1502.  
  1503. /*
  1504. ** This routine is called whenever we think we've got
  1505. ** a complete packet to satisfy a CMD_READ request.
  1506. */
  1507. VOID GotPacket(struct SLIPDevUnit *sdu, ULONG length)
  1508. {
  1509.     struct IOSana2Req *ios2;
  1510.     struct BufferManagement *bm;
  1511.  
  1512.     /* We ignore zero-length packets. These occur
  1513.        in between legal SLIP packets due to the
  1514.        way SLIP packets are framed. */
  1515.  
  1516.     if(length)
  1517.     {
  1518.         PacketReceived(sdu,length);
  1519.     ObtainSemaphore(&sdu->sdu_ListLock);
  1520.  
  1521.     ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx);
  1522.  
  1523.     if(!ios2)
  1524.         ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_RxOrph);
  1525.  
  1526.     ReleaseSemaphore(&sdu->sdu_ListLock);
  1527.  
  1528.     if(ios2)
  1529.     {
  1530.         bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
  1531.  
  1532.         /* Copy the data into the protocol stack's buffer using its
  1533.            supplied callback routine. */
  1534.         if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,sdu->sdu_RxBuff,length))
  1535.         {
  1536.         ios2->ios2_DataLength =    length;
  1537.         }
  1538.         else
  1539.         {
  1540.         ios2->ios2_DataLength =    0;
  1541.         ios2->ios2_Req.io_Error    = S2ERR_NO_RESOURCES;
  1542.         ios2->ios2_WireError = S2WERR_BUFF_ERROR;
  1543.         DoEvent(sdu,S2EVENT_BUFF);
  1544.         }
  1545.         TermIO(ios2);
  1546.     }
  1547.     else
  1548.         PacketDropped(sdu);
  1549.     }
  1550.     sdu->sdu_Escape = 0;
  1551. }
  1552.  
  1553. /*
  1554. ** This routine is called whenever we need to
  1555. ** get more data from the serial port.  We first
  1556. ** to a SDCMD_QUERY to see how much data is available,
  1557. ** if any.
  1558. */
  1559. VOID QueueSerRequest(struct SLIPDevUnit *sdu)
  1560. {
  1561.     sdu->sdu_SerRx->IOSer.io_Command = SDCMD_QUERY;
  1562.     DoIO((struct IORequest *)sdu->sdu_SerRx);
  1563.  
  1564.     if(sdu->sdu_State & SLIPUF_CD)
  1565.     {
  1566.         if(sdu->sdu_SerRx->io_Status & (1<<5))
  1567.         {
  1568.             /* Oops! We've lost carrier. Go offline. */
  1569.             CloseSerial(sdu);
  1570.             DoOffline(sdu);
  1571.             DoEvent(sdu,S2EVENT_OFFLINE);
  1572.             return;
  1573.         }
  1574.     }
  1575.     sdu->sdu_SerRx->IOSer.io_Command = CMD_READ;
  1576.     sdu->sdu_SerRx->IOSer.io_Data = sdu->sdu_RxSLIP;
  1577.     sdu->sdu_SerRx->IOSer.io_Length = sdu->sdu_SerRx->IOSer.io_Actual;
  1578.  
  1579.     /* If the number of bytes available is zero, queue a request
  1580.        for one byte. */
  1581.     if(!sdu->sdu_SerRx->IOSer.io_Length)
  1582.         sdu->sdu_SerRx->IOSer.io_Length = 1;
  1583.  
  1584.     SendIO((struct IORequest *)sdu->sdu_SerRx);
  1585. }
  1586.  
  1587. /*
  1588. ** This is the C entry point for the Unit process.
  1589. ** A6 has been set up by the assembly stub in slip_dev.asm.
  1590. */
  1591.  
  1592. VOID ASM DevProcCEntry(VOID)
  1593. {
  1594.     struct Process *proc;
  1595.     struct SLIPDevUnit *sdu;
  1596.     struct IOExtSer *ioser;
  1597.     struct StartupMessage *sm;
  1598.     struct BufferManagement *bm;
  1599.     struct IOSana2Req *ios2;
  1600.     ULONG waitmask,signals;
  1601.     UBYTE signalbit;
  1602.  
  1603.     /* Find our Process pointer and wait for our startup
  1604.        message to arrive. */
  1605.  
  1606.     proc = (struct Process *)FindTask(0L);
  1607.  
  1608.     WaitPort(&proc->pr_MsgPort);
  1609.  
  1610.     /* Pull the startup message off of our process messageport. */
  1611.     sm = (struct StartupMessage *)GetMsg(&proc->pr_MsgPort);
  1612.  
  1613.     /* Grab our Unit pointer. */
  1614.     sdu = (struct SLIPDevUnit *)sm->Unit;
  1615.  
  1616.     /* Attempt to allocate a signal bit for our Unit MsgPort. */
  1617.     signalbit = AllocSignal(-1L);
  1618.     if(signalbit != -1)
  1619.     {
  1620.         /* Set up our Unit's MsgPort. */
  1621.         sdu->sdu_Unit.unit_MsgPort.mp_SigBit = signalbit;
  1622.         sdu->sdu_Unit.unit_MsgPort.mp_SigTask = (struct Task *)proc;
  1623.         sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
  1624.  
  1625.     /* Initialize our list semaphore */
  1626.     InitSemaphore(&sdu->sdu_ListLock);
  1627.  
  1628.     /* Initialize our linked lists. */
  1629.         NewList((struct List *)&sdu->sdu_Rx);
  1630.         NewList((struct List *)&sdu->sdu_RxOrph);
  1631.         NewList((struct List *)&sdu->sdu_Tx);
  1632.         NewList((struct List *)&sdu->sdu_Events);
  1633.         NewList((struct List *)&sdu->sdu_BuffMgmt);
  1634.         NewList((struct List *)&sdu->sdu_Track);
  1635.  
  1636.     /* Initialize the serial stuff.  If all goes okay,
  1637.        set sdu->sdu_Proc to pointer to our unit process.
  1638.        This will let the Unit init code know that were
  1639.        are okay. */
  1640.  
  1641.     if(InitSerial(sdu))
  1642.             sdu->sdu_Proc = proc;
  1643.     }
  1644.     /* Reply to our startup message */
  1645.     ReplyMsg((struct Message *)sm);
  1646.  
  1647.     /* Check sdu->sdu_Proc to see if everything went okay up
  1648.        above. */
  1649.     if(sdu->sdu_Proc)
  1650.     {
  1651.         waitmask = (1L<<signalbit) | (1L<<sdu->sdu_RxPort->mp_SigBit) |
  1652.                (1L<<sdu->sdu_TxPort->mp_SigBit) | SIGBREAKF_CTRL_F;
  1653.  
  1654.     /* Loop...*/
  1655.  
  1656.         while(TRUE)
  1657.         {
  1658.         signals = Wait(waitmask);
  1659.  
  1660.         /* Have we been signaled to shut down? */
  1661.         if(signals & SIGBREAKF_CTRL_F)
  1662.             break;
  1663.  
  1664.         /* I use this flag to make sure I don't sit idle
  1665.            with a message sitting on one of my message ports. */
  1666.  
  1667.             sdu->sdu_NoMore = TRUE;    /* Make sure we run at least once. */
  1668.  
  1669.             while(sdu->sdu_NoMore)
  1670.             {
  1671.                 sdu->sdu_NoMore = FALSE;
  1672.  
  1673.                 if(ios2 = (struct IOSana2Req *)GetMsg((struct MsgPort *)sdu))
  1674.                 {
  1675.                     sdu->sdu_NoMore = TRUE;
  1676.                     PerformIO(ios2);
  1677.                 }
  1678.                 if(ioser = (struct IOExtSer *)GetMsg(sdu->sdu_RxPort))
  1679.                 {
  1680.                     if(sdu->sdu_State & SLIPUF_ONLINE)
  1681.                     {
  1682.                         DoSerial(sdu, ioser);
  1683.                     }
  1684.                 }
  1685.                 if(ioser = (struct IOExtSer *)GetMsg(sdu->sdu_TxPort))
  1686.                 {
  1687.                     ServiceTxPort(sdu);
  1688.                 }
  1689.             }
  1690.         }
  1691.         /* If we're online, we need to shut everything down. */
  1692.         if(sdu->sdu_State & SLIPUF_ONLINE)
  1693.         {
  1694.             CloseSerial(sdu);
  1695.         FreeSignal(signalbit);
  1696.         while(bm = (struct BufferManagement *)RemHead((struct List *)&sdu->sdu_BuffMgmt))
  1697.             FreeMem(bm,sizeof(struct BufferManagement));
  1698.  
  1699.     }
  1700.         DeinitSerial(sdu);
  1701.  
  1702.         /* Signal the other side we're exiting.  Make sure that
  1703.            we exit before they wake up by using the same trick
  1704.            when replying to Workbench startup messages. */
  1705.  
  1706.         Forbid();
  1707.         Signal((struct Task *)sdu->sdu_Proc,SIGBREAKF_CTRL_F);
  1708.     }
  1709.     /* Something went wrong in the init code.  Drop out. */
  1710.     else
  1711.     {
  1712.         if(signalbit)
  1713.             FreeSignal(signalbit);
  1714.     }
  1715. }
  1716.  
  1717. /* List init routine. */
  1718. VOID NewList(struct List *list)
  1719. {
  1720.     list->lh_Head = (struct Node *)&list->lh_Tail;
  1721.     list->lh_Tail = NULL;
  1722.     list->lh_TailPred = (struct Node *)list;
  1723. }
  1724.